package com.smart.lx.proxy.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 功能描述: <br>
 * 〈cglib进行动态代理〉
 *
 * @since: 1.0.0
 * @Author:abc
 * @Date: 2019/4/5
 * CGLIB Proy特点:
 * 	* 通过动态继承目标对象的方式实现动态代理;
 * 	* 被代理类不需要实现任何接口;
 *
 * * CGLIB Proxy生产代理类过程:
 * 	1. 生成代理对象方法: enhancer.create(clazz, args);
 * 		* clazzes: target的类;
 * 		* args : 构造器参数;
 * 	2. 判断是否需要动态生成proxy的字节码文件;
 * 		* enhancer.setCallback(Enhancer proxyEnhancer); //设置提供增强方法的enhancer;
 * 		* cglib 通过proxyEnhancer和clazz判断是否需要生成字节码文件;
 * 	3. 生成字节码文件:
 * 		* 使用ASM框架生成2个字节码文件:
 * 			* targetClass, proxyClass
 * 			* 会为新targetClass和proxyClass中的方法编号;(为FASTClass做准备)
 * 		* proxyClass重写target中的所有方法:
 * 			* 所有重写的方法都执行 2步骤proxyEnhancer中 的intercept(Object obj, Method method, Object[] args, MethodProxy proxy)方法
 * 				* 因为1步骤中enhancer.create(clazz, args)时注入了target构造参数, 所以proxyClass可以持有target对象;
 * 		* 生成字节码文件较为复杂, 相对于JDK效率较低;
 * 	4. 动态生成字节码文件;
 * 	5. 动态加载字节码文件;
 * 	6. 创建proxy和target对象;
 *
 * * FASTCLASS技术:
 * 	* 当CGLIB第一次调用代理方法时, 会产生一个FASTCLASS的字节码文件;
 * 	* FASTCLASS文件中存储 proxy和target方法的对应关系;
 * 		* 根据步骤3中, targetClass和proxyClass中方法的编号
 * * CGLIB中proxy调用target方法:
 * 	* Object objr = proxy.invokeSuper(obj, args);
 * 	* 使用FASTCLASS技术, 快速找到对应的target中的方法;
 * 	* 执行方法效率高于JDK PROXY的反射技术;
 */
public class ProxyForCglib implements MethodInterceptor {
    private Object obj;
    public Object getInstance(Object obj){
        this.obj = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(this);
        enhancer.setSuperclass(obj.getClass());


        Class [] clazzes = {String.class};
        String [] args = {obj.toString()};
        return enhancer.create(clazzes, args);
    }



    public void before(){
        System.out.println("获取快捷方式路径");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        System.out.println(o.getClass());  //o;
        Object objr = methodProxy.invokeSuper(o, objects);
        return objr;
    }
}
